home *** CD-ROM | disk | FTP | other *** search
- /********************************************************/
- /* Moon Module for SkyView */
- /* */
- /* (c)1992 N P Hawkes */
- /* */
- /* Displays the Moon. */
- /********************************************************/
-
- #include "menu.h"
- #include "dbox.h"
- #include "bbc.h"
- #include "wimpt.h"
- #include "dbox.h"
- #include "string.h"
- #include "sprite.h"
- #include "res.h"
- #include "resspr.h"
-
- #include "sv_header.h"
- #include "datime.h"
- #include "radec.h"
- #include "ecliptic.h"
- #include "riset.h"
- #include "moon.h"
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
-
- /********************************************************/
- /* Constants */
- /********************************************************/
- #define DISP_NAME "The Moon" /* Entry in Display menu. */
- #define SEL_NAME "The Moon" /* Entry in Select menu. */
-
- /* Set effective altitude of horizon for calculations */
- /* of rising and setting. */
- #define HORALT (REAL)0.0088
-
- #define CONVERGE 5 /* Convergence criterion in */
- /* phenomenon calculations. */
- #define MAX_ITER 5 /* Max no. of iterations. */
-
- #define NUM_SPR 4 /* Number of different Moon */
- /* symbols (for diff. ages).*/
- #define SPRNAM_MAX 13 /* Max len of spr name, +1. */
-
- /********************************************************/
- /* Global Variables */
- /********************************************************/
- static BOOL display_flag = TRUE; /* 'Enabled' flag. */
- static int moduleid; /* Module ID. */
- static int horiz_id; /* Moon's ID in Horiz window. */
- static int vert_id; /* Moon's ID in Vert window. */
- static REAL moonra; /* Right Ascension of Moon. */
- static REAL moondec; /* Declination of Moon. */
- static REAL moonage; /* Age of Moon. */
- static int moon_symbol;/* Which Moon sprite to use. */
-
- /* Array of (address-type) sprite_ids for Moon symbols: */
- static sprite_id moon_spr[NUM_SPR];
-
- /********************************************************/
- /* Function Prototypes */
- /********************************************************/
- static BOOL make_sprite_id(char *namestr, int i, sprite_id *idptr);
- static BOOL make_sprite_name(char *namestr, int i, char *spr_name);
- static void moon_buildfn(void);
- static void moon_altaz(REAL *altptr, REAL *azimptr);
- static void age(REAL *ageptr, int *symbolptr);
- static void moon_altaz_any(observerstr *ptr, int hour, int min,
- REAL *altptr, REAL *azimptr);
- static void moon_radecfn(int id, observerstr *ob_ptr, int hour, int min,
- REAL *traptr, REAL *tdecptr);
- static void geocentric_rradec(double jul,
- REAL *rptr, REAL *raptr, REAL *decptr);
- static void topocentric_radec(observerstr *ob_ptr, REAL sid,
- REAL r, REAL ra, REAL dec,
- REAL *traptr, REAL *tdecptr);
- static void geocentric_elatlong(double jul,
- REAL *elatptr, REAL *elongptr, double *pptr);
- static void moon_selectfn(selectfn_reasoncode reason);
- static void selection_details(void);
- static BOOL cul_calc(REAL altmin,
- REAL *altptr, REAL *azimptr, int *hourptr, int *minptr);
- static BOOL rs_calc(BOOL whichcalc,
- REAL *altptr, REAL *azimptr, int *hourptr, int *minptr);
- static BOOL moon_displayfn(BOOL *enabptr);
- static os_error *moon_plotfn(int x, int y, int id);
- static void moon_infofn(int id);
-
- /********************************************************/
- /* Initialisation Function */
- /********************************************************/
- BOOL moon_initfn(int moduleno, modulestr *moon)
- {
- int i;
-
- moduleid = moduleno;
-
- moon->buildfn = moon_buildfn;
- moon->selectfn = moon_selectfn;
- moon->dispfn = moon_displayfn;
- moon->infofn = moon_infofn;
- moon->initial = display_flag;
- moon->display_entry = DISP_NAME;
- moon->display_menu = NULL;
- moon->select_entry = SEL_NAME;
- moon->select_menu = NULL;
-
- /* Construct an array of address-type sprite_ids, each */
- /* for a different age of the Moon. Quit if error. */
- for (i = 0; i < NUM_SPR; i++)
- if (!make_sprite_id("moon", i, moon_spr + i)) return FALSE;
-
- return TRUE;
- }
-
- /*------------------------------------------------------*/
- /* Function to build an address-type sprite id corr- */
- /* esponding to the sprite name returned by the function*/
- /* make_sprite_name. Returns TRUE if no errors detected.*/
- /*------------------------------------------------------*/
- static BOOL make_sprite_id(char *namestr, int i, sprite_id *idptr)
- {
- char spr_name[SPRNAM_MAX]; /*For built-up sprite name.*/
- sprite_id nametype_id;
-
- /* Construct sprite name. */
- if (!make_sprite_name(namestr, i, spr_name)) return FALSE;
-
- /* Form a name-type sprite id using this name. */
- nametype_id.s.name = spr_name;
- nametype_id.tag = sprite_id_name;
-
- /* Get address of sprite. Quit if error. */
- if (sprite_select_rp(resspr_area(),
- &nametype_id,
- &idptr->s.addr) != NULL) return FALSE;
-
- /* Set tag to identify *idptr as an address-type id. */
- idptr->tag = sprite_id_addr;
-
- return TRUE;
- }
-
- /*------------------------------------------------------*/
- /* Function to make a sprite name from the given string */
- /* namestr and the given integer i. The name made is of*/
- /* the form ssssnnn, where ssss is the first 9 chars of */
- /* the given string (fewer if the string is shorter) and*/
- /* nnn is the integer i expressed as 3 digits (000-999).*/
- /* String pointed to by spr_name is assumed long enough.*/
- /* Return FALSE if error detected. */
- /*------------------------------------------------------*/
- static BOOL make_sprite_name(char *namestr, int i, char *spr_name)
- {
- int len;
-
- if (i<0 || i>999) return FALSE;
-
- /* Copy at most 9 chars from namestr to spr_name. */
- strncpy(spr_name, namestr, 9);
-
- /* Add number. */
- len = strlen(namestr);
- if (len > 9) len = 9;
- sprintf(spr_name+len, "%03i", i);
-
- return TRUE;
- }
-
-
- /********************************************************/
- /* List-Building Function */
- /********************************************************/
- static void moon_buildfn(void)
- {
- plotobj the_moon;
- /* Bounding box of plotting symbol, relative to */
- /* position of symbol: */
- wimp_box size = {-12, -12, 14, 14};
-
- /* Choose to rebuild list regardless of whether or not */
- /* this module is enabled. */
-
- /* Set up the one and only object owned by this module. */
- the_moon.id = 0;
- the_moon.module = moduleid;
- the_moon.plotfn = moon_plotfn;
- moon_altaz(&the_moon.alt, &the_moon.azim);
- the_moon.size = size;
-
- /* Add this object to the plotting lists. */
- addobj(the_moon, &horiz_id, &vert_id);
-
- /* Also calculate age, and which moon symbol to use. */
- age(&moonage, &moon_symbol);
-
- return;
- }
-
- /*------------------------------------------------------*/
- /* Function to calculate the Moon's current alt & azim. */
- /*------------------------------------------------------*/
- static void moon_altaz(REAL *altptr, REAL *azimptr)
- {
- REAL r; /* Moon-Earth dist (in Earth radii).*/
- REAL ra, dec; /* Geocentric RA and Dec of Moon. */
-
- /* Get the current geocentric RA and Dec of the Moon, */
- /* and its distance from the Earth. */
- geocentric_rradec(ob_data.jul, &r, &ra, &dec);
-
- /* Convert to topocentric RA and Dec. */
- topocentric_radec(&ob_data, ob_data.sid, r, ra, dec, &moonra, &moondec);
-
- /* Convert to altitude and azimuth. */
- radec_altaz(moonra, moondec, &ob_data, ob_data.sid, altptr, azimptr);
-
- return;
- }
-
- /*------------------------------------------------------*/
- /* Function to calculate Moon's alt & azim at any */
- /* hour & min of the day specified in the given */
- /* observerstr (which also specifies the location). */
- /*------------------------------------------------------*/
- static void moon_altaz_any(observerstr *ptr, int hour, int min,
- REAL *altptr, REAL *azimptr)
- {
- REAL r; /* Moon-Earth dist (in Earth radii). */
- REAL ra, dec; /* Geocentric RA and Dec of Moon. */
- REAL tra, tdec; /* Topocentric RA and Dec of Moon. */
- double jul; /* Days since noon GMT 0/1/1900. */
- REAL sid; /* Local siderial time. */
-
- jul = datime_julian(ptr, hour, min);
- sid = datime_siderial(ptr, jul, hour, min);
-
- /* Get dist & geocentric RA and Dec. */
- geocentric_rradec(jul, &r, &ra, &dec);
-
- /* Convert to topocentric RA and Dec. */
- topocentric_radec(ptr, sid, r, ra, dec, &tra, &tdec);
-
- /* Convert to altitude and azimuth. */
- radec_altaz(tra, tdec, ptr, sid, altptr, azimptr);
-
- return;
- }
-
- /*------------------------------------------------------*/
- /* Function to calculate the topocentric RA & Dec of */
- /* the Moon at a specified instant. The parameters of */
- /* this function conform to the requirements of the */
- /* 'Riset' functions. */
- /*------------------------------------------------------*/
- static void moon_radecfn(int id, observerstr *ob_ptr, int hour, int min,
- REAL *traptr, REAL *tdecptr)
- {
- /* 'id' is not used as there is only one Moon. */
-
- REAL r; /* Moon-Earth dist (in Earth radii). */
- REAL ra, dec; /* Geocentric RA and Dec of Moon. */
- double jul; /* Days since noon GMT 0/1/1900. */
- REAL sid; /* Local siderial time. */
-
- jul = datime_julian(ob_ptr, hour, min);
- sid = datime_siderial(ob_ptr, jul, hour, min);
-
- /* Get dist & geocentric RA and Dec. */
- geocentric_rradec(jul, &r, &ra, &dec);
-
- /* Convert to topocentric RA and Dec. */
- topocentric_radec(ob_ptr, sid, r, ra, dec, traptr, tdecptr);
-
- return;
- }
-
- /*------------------------------------------------------*/
- /* Function to calculate the geocentric RA and Dec of */
- /* the Moon, and its dist from Earth (in Earth radii). */
- /*------------------------------------------------------*/
- static void geocentric_rradec(double jul,
- REAL *rptr, REAL *raptr, REAL *decptr)
- {
- double T; /* Centuries since noon GMT 0/1/1900. */
- double p; /* Horizontal parallax. */
- double r; /* Distance from Earth. */
- REAL elatit; /* Geocentric ecliptic latitude. */
- REAL elongit; /* Geocentric ecliptic longitude. */
-
- /* Get geocent. eclipt. lat & long, and horiz. parallax.*/
- geocentric_elatlong(jul, &elatit, &elongit, &p);
-
- /* Convert to geocentric RA and Dec. */
- T = jul/36525.0;
- ecliptic_radec(elatit, elongit, T, raptr, decptr);
-
- /* Calculate distance from Earth. */
- r = 1.0 / sin(p);
- *rptr = (REAL)r;
-
- return;
- }
-
- /*------------------------------------------------------*/
- /* Function to calculate the geocentric ecliptic */
- /* latitude and longitude of the Moon, and the */
- /* horizontal parallax, at the instant implied by jul */
- /* (No. of days since noon GMT on 0/1/1900). Based on */
- /* algorithm in NAO Technical Note No.46, Jan 1978, */
- /* page 28. Angles in radians. */
- /*------------------------------------------------------*/
- static void geocentric_elatlong(double jul,
- REAL *elatptr, REAL *elongptr, double *pptr)
- {
- double M1, L, M, N, F, tN;
- double beta, lambda;
-
- M1 = DblCONV*fmod(358.48 + 0.985600*jul, 360.0);
- L = fmod(270.43 + 13.176397*jul, 360.0);
- M = DblCONV*fmod(296.10 + 13.064992*jul, 360.0);
- N = DblCONV*fmod(350.74 + 12.190749*jul, 360.0);
- F = DblCONV*fmod( 11.25 + 13.229350*jul, 360.0);
-
- tN = 2.0*N;
-
- /* Geocentric ecliptic latitude: */
- beta = 5.128 * sin(F)
- + 0.281 * sin(M + F)
- + 0.278 * sin(M - F)
- + 0.173 * sin(tN - F)
- - 0.055 * sin(M - tN - F)
- - 0.046 * sin(M - tN + F)
- + 0.033 * sin(tN + F);
- if (beta < 0.0) beta += 360.0;
- if (beta >= 360.0) beta = 0.0;
- *elatptr = CONV * (REAL)beta;
-
- /* Geocentric ecliptic longitude: */
- lambda = L
- + 6.289 * sin(M)
- - 1.274 * sin(M - tN)
- + 0.658 * sin(tN)
- + 0.214 * sin(2.0*M)
- - 0.186 * sin(M1)
- - 0.114 * sin(2.0*F)
- - 0.059 * sin(2.0*M - tN)
- - 0.057 * sin(M1 + M - tN)
- + 0.053 * sin(M + tN)
- - 0.046 * sin(M1 - tN)
- + 0.041 * sin(M - M1)
- - 0.035 * sin(N)
- - 0.030 * sin(M + M1);
- if (lambda < 0.0) lambda += 360.0;
- if (lambda >= 360.0) lambda -= 360.0;
- if (lambda < 0.0) lambda = 0.0;
- *elongptr = CONV * (REAL)lambda;
-
- /* Parallax: */
- *pptr = 0.9507
- + 0.0518 * cos(M)
- + 0.0095 * cos(M - tN)
- + 0.0078 * cos(tN)
- + 0.0028 * cos(2.0*M);
- *pptr *= DblCONV;
-
- return;
- }
-
- /*------------------------------------------------------*/
- /* Function to convert geocentric RA and Dec to */
- /* (approx) topocentric RA and Dec. Formula from */
- /* Astronomical Almanac 1990, p. D46. */
- /*------------------------------------------------------*/
- static void topocentric_radec(observerstr *ob_ptr, REAL sid,
- REAL r, REAL ra, REAL dec,
- REAL *traptr, REAL *tdecptr)
- {
- double x, y, z; /* Geocentric rectangular coords. */
- double x1, y1, z1; /* Topocentric rectangular coords. */
- double r1;
- double tra, tdec;
- double sintdec;
-
- /* Get geocentric rectangular coords. */
- x = (double)r * cos((double)dec) * cos((double)ra);
- y = (double)r * cos((double)dec) * sin((double)ra);
- z = (double)r * sin((double)dec);
-
- /* Derive topocentric rectangular coords. */
- x1 = x - cos((double)ob_ptr->latit) * cos((double)sid);
- y1 = y - cos((double)ob_ptr->latit) * sin((double)sid);
- z1 = z - sin((double)ob_ptr->latit);
- r1 = sqrt(x1*x1 + y1*y1 + z1*z1);
-
- /* Derive topocentric RA. */
- if (fabs(x1) < 1.0E-7 && fabs(y1) < 1.0E-7)
- tra = 0.0;
- else
- {
- tra = atan2(y1, x1);
- if (tra < 0.0) tra += DblTWO_PI;
- if (tra >= DblTWO_PI) tra = 0.0;
- }
- *traptr = (REAL)tra;
-
- /* Derive topocentric Dec. */
- sintdec = z1 / r1;
- if (sintdec < -1.0) sintdec = -1.0;
- if (sintdec > 1.0) sintdec = 1.0;
- tdec = asin(sintdec);
- *tdecptr = (REAL)tdec;
-
- return;
- }
-
- /*------------------------------------------------------*/
- /* Function to calculate the approximate age of the */
- /* Moon, and decide which symbol to use. */
- /*------------------------------------------------------*/
- static void age(REAL *ageptr, int *symbolptr)
- {
- double T; /* Centuries since noon GMT on 0/1/1900. */
- double a, b, c;
- double delta;
-
- T = ob_data.jul / 36525.0;
- b = DblCONV * fmod(296.1 + 477198.75 * T, 360.0);
- c = DblCONV * fmod(358.5 + 35999.04 * T, 360.0);
- a = 350.74 + 445267.14*T + 6.3*sin(b) - 1.9*sin(c);
-
- delta = fmod(a, 360.0);
- *ageptr = (REAL)0.082 * (REAL)delta;
-
- /* Divide synodic month into NUM_SPR intervals, with */
- /* offset so that same symbol is used for just before & */
- /* just after new moon. Return a number in the range */
- /* 0 (nearest new moon) to NUM_SPR-1. */
- delta += 180.0 / (double)NUM_SPR;
- if (delta >= 360.0) delta -= 360.0;
- if (delta < 0.0) delta = 0.0;
- delta /= 360.0;
- delta *= (double)NUM_SPR;
- *symbolptr = (int)delta;
- if (*symbolptr < 0) *symbolptr = 0;
- if (*symbolptr >= NUM_SPR) *symbolptr = NUM_SPR - 1;
-
- return;
- }
-
-
- /********************************************************/
- /* Object-Selecting Function */
- /********************************************************/
- static void moon_selectfn(selectfn_reasoncode reason)
- {
- switch (reason)
- {
- case new_selection:
- /* Only one Moon, so selection always succeeds. */
- selection.id = 0;
- selection.selected_OK = TRUE;
- case window_selection:
- /* Selection has been made by clicking in a */
- /* window. */
- case recalculate_data:
- /* Observer details have changed, and plotting */
- /* lists have been rebuilt. */
- /* */
- /* Fill in the details of rising, setting etc. */
- selection_details();
- break;
-
- case timeonly_recalculate:
- /* As recalculate_data, but only the time of day */
- /* (and possibly the direction of view - this is */
- /* is of no interest) have changed. */
- /* This simplifies the calculation. */
- selection.horiz_id = horiz_id;
- selection.vert_id = vert_id;
- /* Decide if it can be seen now. */
- selection.now = selection.horiz_id != NOWHERE || \
- selection.vert_id != NOWHERE;
- break;
-
- case sel_info_request:
- /* Write info into text buffer. Use Info fn. */
- moon_infofn(0);
- break;
-
- default:
- /* Unknown option. Do nothing. */
- break;
-
- }
-
- return;
- }
-
- /*------------------------------------------------------*/
- /* Function to fill in the details of rising, setting */
- /* and culminating. */
- /*------------------------------------------------------*/
- static void selection_details(void)
- {
- REAL rise_alt; /*Altitude at calculated rising time. */
- REAL set_alt; /*Altitude at calculated setting time.*/
-
- selection.horiz_id = horiz_id;
- selection.vert_id = vert_id;
- selection.now = selection.horiz_id != NOWHERE || \
- selection.vert_id != NOWHERE;
-
- selection.culminating = cul_calc(HORALT,
- &selection.cul_alt,
- &selection.cul_azim,
- &selection.cul_hour,
- &selection.cul_min);
- selection.rising = rs_calc(RISECALC,
- &rise_alt,
- &selection.rise_azim,
- &selection.rise_hour,
- &selection.rise_min);
- selection.setting = rs_calc(SETCALC,
- &set_alt,
- &selection.set_azim,
- &selection.set_hour,
- &selection.set_min);
- return;
- }
-
- /*------------------------------------------------------*/
- /* Function to derive details of culmination. */
- /* If Moon culminates, fn finds alt, azim, hour & min */
- /* and returns TRUE. Returns FALSE if no culmination. */
- /*------------------------------------------------------*/
- static BOOL cul_calc(REAL altmin,
- REAL *altptr, REAL *azimptr, int *hourptr, int *minptr)
- {
- BOOL ok;
-
- /* Guess a time of day. Take midday. */
- *hourptr = 12;
- *minptr = 0;
-
- /* Try to improve guessed time. */
- ok = riset_cul(
- &ob_data, MAX_ITER, CONVERGE, moon_radecfn, 0, hourptr, minptr);
-
- /* Give up if time did not converge. */
- if (!ok) return FALSE;
-
- /* Check that Moon would be higher than 'altmin'. */
- moon_altaz_any(&ob_data, *hourptr, *minptr, altptr, azimptr);
- return (*altptr >= altmin);
- }
-
- /*------------------------------------------------------*/
- /* Function to derive details of rising or setting. */
- /* If phenomenon occurs, fn finds alt, azim, hour & min */
- /* and returns TRUE. Returns FALSE otherwise. */
- /*------------------------------------------------------*/
- static BOOL rs_calc(BOOL whichcalc,
- REAL *altptr, REAL *azimptr, int *hourptr, int *minptr)
- {
- BOOL ok;
-
- /* Guess a time of day. Take midday. */
- *hourptr = 12;
- *minptr = 0;
-
- /* Try to improve this guess. */
- ok = riset_riset(&ob_data, MAX_ITER, CONVERGE, moon_radecfn, 0,
- whichcalc, HORALT, hourptr, minptr);
-
- /* Give up if time did not converge to a valid value. */
- if (!ok) return FALSE;
-
- /* Check that Moon is indeed visible at this time. */
- moon_altaz_any(&ob_data, *hourptr, *minptr, altptr, azimptr);
- return (*altptr > ZERO);
- }
-
-
- /********************************************************/
- /* Display Function */
- /********************************************************/
- static BOOL moon_displayfn(BOOL *enabptr)
- {
- /* Toggle Enable/Disable flag. */
- display_flag = !display_flag;
-
- /* Inform main program of new status. */
- *enabptr = display_flag;
-
- /* Data in plotting list is always kept up-to-date, so */
- /* no need to check validity or call list-building fn. */
-
- /* Windows will always need updating. */
- return TRUE;
- }
-
-
- /********************************************************/
- /* Plotting Function */
- /********************************************************/
- static os_error *moon_plotfn(int x, int y, int id)
- {
- return sv_plotsprite(&moon_spr[moon_symbol], MODE_20, x, y, 5, 5);
- }
-
-
- /********************************************************/
- /* Info Function */
- /********************************************************/
- static void moon_infofn(int id)
- {
- char p_text[RADEC_TEXTLEN]; /*Text buff for RA & Dec.*/
-
- /* Get RA and Dec in text form. */
- radec_text(moonra, moondec, p_text);
-
- sprintf(infoptr, "%s\n\nApprox age %.1f days\n%s",
- "The Moon",
- (double)moonage,
- p_text);
-
- return;
- }
-